package org.nobody.mallb2c.mallcart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.nobody.common.constant.CartConstant;
import org.nobody.common.utils.R;
import org.nobody.mallb2c.mallcart.feign.ProductFeignService;
import org.nobody.mallb2c.mallcart.interceptor.CartInterceptor;
import org.nobody.mallb2c.mallcart.service.CartService;
import org.nobody.mallb2c.mallcart.to.UserInfoTo;
import org.nobody.mallb2c.mallcart.vo.Cart;
import org.nobody.mallb2c.mallcart.vo.CartItem;
import org.nobody.mallb2c.mallcart.vo.SkuInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author 3489309323@qq.com
 * @create 2020-09-19-18:53
 */
@Slf4j
@Service
public class CartServiceImpl implements CartService {
  @Autowired
  StringRedisTemplate redisTemplate;

  @Autowired
  ProductFeignService productFeignService;

  @Autowired
  ThreadPoolExecutor executor;

  @Override
  public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
    BoundHashOperations<String, Object, Object> cartOps = getCartOps();
    String res = (String) cartOps.get(skuId.toString());
    //购物车无此商品
    if (StringUtils.isEmpty(res)) {
      CartItem cartItem = new CartItem();
      //添加新商品到购物车
      CompletableFuture<Void> getSkuInfoTask = CompletableFuture.runAsync(() -> {
        //远程查询当前要添加的商品的信息
        R skuInfo = productFeignService.getSkuInfo(skuId);
        SkuInfoVo data = skuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
        });
        cartItem.setCheck(true);
        cartItem.setCount(num);
        cartItem.setImage(data.getSkuDefaultImg());
        cartItem.setTitle(data.getSkuTitle());
        cartItem.setSkuId(skuId);
        cartItem.setPrice(data.getPrice());
      }, executor);

      CompletableFuture<Void> getSkuSaleAttrValues = CompletableFuture.runAsync(() -> {
        //远程查询sku的组合信息
        List<String> values = productFeignService.getSkuSaleAttrValues(skuId);
        cartItem.setSkuAttr(values);
      }, executor);

      CompletableFuture.allOf(getSkuInfoTask, getSkuSaleAttrValues).get();
      String s = JSON.toJSONString(cartItem);
      cartOps.put(skuId.toString(), s/*如果你传的不是字符串给redis,redis默认会采用jdk的序列化进行序列化,将对象转成字符流传给redis.  故这里为了方便,我们预先将其序列化成了字符串*/);

      return cartItem;

      // 购物车有此商品,修改数量即可
    } else {
      CartItem cartItem = JSON.parseObject(res, CartItem.class);
      cartItem.setCount(cartItem.getCount() + num);

      cartOps.put(skuId.toString(), JSON.toJSONString(cartItem));

      return cartItem;
    }
  }

  @Override
  public CartItem getCartItem(Long skuId) {
    BoundHashOperations<String, Object, Object> cartOps = getCartOps();
    String str = (String) cartOps.get(skuId.toString());
    CartItem cartItem = JSON.parseObject(str, CartItem.class);
    return cartItem;
  }

  @Override
  public Cart getCart() throws ExecutionException, InterruptedException {
    Cart cart = new Cart();
    UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
    if (userInfoTo.getUserId() != null) {
      //1、 登录
      //1.1 如果临时购物车的数据还没有进行合并,需要进行合并
      String tempCartKey = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
      List<CartItem> tempCartItems = getCartItems(tempCartKey);
      if (tempCartItems != null && tempCartItems.size() > 0) {
        //历史购物车有数据,需要合并
        for (CartItem tempCartItem : tempCartItems) {
          addToCart(tempCartItem.getSkuId(), tempCartItem.getCount());
        }
        //清除临时购物车的数据
        clearCart(tempCartKey);
      }
      //1.2 获取登录后的购物车的数据【包含合并过来的临时购物车的数据】
      String cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserId();
      List<CartItem> cartItems = getCartItems(cartKey);
      cart.setItems(cartItems);

    } else {
      //2、 没登录
      //获取临时购物车的所有购物项
      String cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
      List<CartItem> cartItems = getCartItems(cartKey);
      cart.setItems(cartItems);
    }

    return cart;
  }

  /**
   * 获取到我们要操作的购物车(指定的redis key对象)
   * <p>
   * 如果没登录 获取临时购物车
   * <p>
   * 有登录 获取用户购物车
   *
   * @return
   */
  private BoundHashOperations<String, Object, Object> getCartOps() {
    UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();

    String cartKey = "";
    //mall:cart:1(userId/userKey)
    cartKey = (userInfoTo.getUserId() != null) ?
      //说明登录了,用用户专属的
      CartConstant.CART_PREFIX + userInfoTo.getUserId() :
      //说明没有登录,用临时的
      CartConstant.CART_PREFIX + userInfoTo.getUserKey();

    BoundHashOperations<String, Object, Object> ops = redisTemplate.boundHashOps(cartKey);

    return ops;
  }

  private List<CartItem> getCartItems(String cartKey) {
    BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(cartKey);
    List<Object> values = hashOps.values();

    if (values != null && values.size() > 0) {
      List<CartItem> collect = values.stream().map(obj -> {
        String str = (String) obj;
        return JSON.parseObject(str, CartItem.class);
      }).collect(Collectors.toList());
      return collect;
    }
    return null;
  }

  @Override
  public void clearCart(String cartKey) {
    redisTemplate.delete(cartKey);
  }

  @Override
  public void checkItem(Long skuId, Integer check) {
    CartItem cartItem = getCartItem(skuId);
    cartItem.setCheck(check == 1 ? true : false);
    String s = JSON.toJSONString(cartItem);
    BoundHashOperations<String, Object, Object> cartOps = getCartOps();
    cartOps.put(skuId.toString(), s);
  }

  @Override
  public void changeItemCount(Long skuId, Integer num) {
    CartItem cartItem = getCartItem(skuId);
    cartItem.setCount(num);

    BoundHashOperations<String, Object, Object> cartOps = getCartOps();
    cartOps.put(skuId.toString(), JSON.toJSONString(cartItem));
  }

  @Override
  public void deleteItem(Long skuId) {
    BoundHashOperations<String, Object, Object> cartOps = getCartOps();
    cartOps.delete(skuId.toString());
  }

  @Override
  public List<CartItem> getUserCartItems() {
    UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
    if (userInfoTo.getUserId() == null) {
      return null;
    }else{
      String cartKey = CartConstant.CART_PREFIX + userInfoTo.getUserId();
      List<CartItem> cartItems = getCartItems(cartKey);
      //获取所有被选中的购物项
      List<CartItem> collect = cartItems.stream()
        .filter(item -> item.getCheck())
        .map(item->{
          //确保为最新价格
          R r = productFeignService.getPrice(item.getSkuId());
          String price = (String) r.get("data");
          item.setPrice(new BigDecimal(price));
          return item;
        })
        .collect(Collectors.toList());
      return collect;
    }
  }
}
